package cn.iocoder.yudao.module.resource.service.usertimemanager.impl;

import cn.hutool.core.util.IdUtil;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.resource.api.enums.UserTimeTransactionTypeEnum;
import cn.iocoder.yudao.module.resource.api.model.timepackage.TimePackagePaySuccessEvent;
import cn.iocoder.yudao.module.resource.controller.admin.usertimebalance.vo.UserTimeBalanceSaveReqVO;
import cn.iocoder.yudao.module.resource.controller.admin.usertimetransaction.vo.UserTimeTransactionSaveReqVO;
import cn.iocoder.yudao.module.resource.dal.dataobject.timepackage.TimePackageDO;
import cn.iocoder.yudao.module.resource.dal.dataobject.usertimebalance.UserTimeBalanceDO;
import cn.iocoder.yudao.module.resource.dal.dataobject.usertimetransaction.UserTimeTransactionDO;
import cn.iocoder.yudao.module.resource.dal.redis.ResourceLockRedisDAO;
import cn.iocoder.yudao.module.resource.service.timepackage.TimePackageService;
import cn.iocoder.yudao.module.resource.service.usertimebalance.UserTimeBalanceService;
import cn.iocoder.yudao.module.resource.service.usertimemanager.IUserTimeManagerService;
import cn.iocoder.yudao.module.resource.service.usertimetransaction.UserTimeTransactionService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service
public class UserTimeManagerServiceImpl implements IUserTimeManagerService {
    @Resource
    private UserTimeTransactionService userTimeTransactionService;
    @Lazy
    @Resource
    private UserTimeBalanceService userTimeBalanceService;
    @Resource
    private ResourceLockRedisDAO resourceLockRedisDAO;
    @Resource
    private TimePackageService timePackageService;

    @EventListener
    public void handleTimePackagePaySuccessEvent(TimePackagePaySuccessEvent event) {
        log.info("收到支付成功Event, event = {}", event);
        final TimePackageDO timePackage = timePackageService.getTimePackage(event.getTimePackageId());
        final Long timeMs = timePackage.getTimeMs();
        purchaseTime(event.getUserId(), UserTimeTransactionTypeEnum.PURCHASE, event.getOrderId(), timeMs);
    }

    @Transactional
    @Override
    public void purchaseTime(Long userId, UserTimeTransactionTypeEnum transactionType, Long orderId, Long timeMs) {
        resourceLockRedisDAO.lockUserTime(userId, () -> {
            // 获取或创建用户时长余额
            UserTimeBalanceDO balance = userTimeBalanceService.getUserTimeBalanceByUserId(userId);
            if (balance == null) {
                balance = new UserTimeBalanceDO();
                balance.setId(IdUtil.objectId());
                balance.setUserId(userId);
                balance.setTotalTimeMs(timeMs);
                balance.setRemainingTimeMs(timeMs);
                userTimeBalanceService.createUserTimeBalance(BeanUtils.toBean(balance, UserTimeBalanceSaveReqVO.class));
                log.info("创建用户时长余额, userId = {}, transactionType = {}, orderId = {}, timeMs = {}, remainingTimeMs = {}",
                        userId, transactionType, orderId, timeMs, balance.getRemainingTimeMs());
            } else {
                // 更新余额
                balance.setTotalTimeMs(balance.getTotalTimeMs() + timeMs);
                balance.setRemainingTimeMs(balance.getRemainingTimeMs() + timeMs);
                userTimeBalanceService.updateUserTimeBalance(BeanUtils.toBean(balance, UserTimeBalanceSaveReqVO.class));
                log.info("更新用户时长余额, userId = {}, transactionType = {}, orderId = {}, timeMs = {}, remainingTimeMs = {}",
                        userId, transactionType, orderId, timeMs, balance.getRemainingTimeMs());
            }

            // 记录交易
            final UserTimeTransactionSaveReqVO transaction = new UserTimeTransactionSaveReqVO();
            transaction.setId(IdUtil.objectId());
            transaction.setUserId(userId);
            transaction.setTransactionType(transactionType.getValue());
            transaction.setTransactionTimeMs(timeMs);
            transaction.setRemainingTimeMs(balance.getRemainingTimeMs());
            transaction.setOrderId(orderId);
            userTimeTransactionService.createUserTimeTransaction(transaction);
            log.info("创建用户时长交易记录-充值, userId = {}, transactionType = {}, orderId = {}, timeMs = {}, remainingTimeMs = {}",
                    userId, transactionType, orderId, timeMs, transaction.getRemainingTimeMs());
            return null;
        });
    }

    @Transactional
    @Override
    public boolean consumeTime(Long userId, String gameMatchId, Integer roleId, String roleName, Long timeMs) {
        return resourceLockRedisDAO.lockUserTime(userId, () -> {
            final UserTimeBalanceDO balance = userTimeBalanceService.getUserTimeBalanceByUserId(userId);
            if (balance == null) {
                log.info("用户时长余额不存在, userId = {}, gameMatchId = {}, timeMs = {}", userId, gameMatchId, timeMs);
                return false;
            }

            if (balance.getRemainingTimeMs() == 0) {
                log.info("用户时长余额为0, userId = {}, gameMatchId = {}, timeMs = {}", userId, gameMatchId, timeMs);
                return false;
            }

            // 更新余额
            balance.setRemainingTimeMs(Math.max(balance.getRemainingTimeMs() - timeMs, 0));
            userTimeBalanceService.updateUserTimeBalance(BeanUtils.toBean(balance, UserTimeBalanceSaveReqVO.class));
            log.info("更新用户时长余额, userId = {}, gameMatchId = {}, timeMs = {}, remainingTimeMs = {}",
                    userId, gameMatchId, timeMs, balance.getRemainingTimeMs());

            // 记录交易
            UserTimeTransactionDO transaction = userTimeTransactionService.getUserTimeTransactionByGameMatchId(gameMatchId);
            if (transaction == null) {
                transaction = new UserTimeTransactionDO();
                transaction.setId(IdUtil.objectId());
                transaction.setUserId(userId);
                transaction.setGameMatchId(gameMatchId);
                transaction.setRoleId(roleId);
                transaction.setRoleName(roleName);
                transaction.setTransactionType(UserTimeTransactionTypeEnum.CONSUME.getValue());
                transaction.setTransactionTimeMs(timeMs);
                transaction.setRemainingTimeMs(balance.getRemainingTimeMs());
                userTimeTransactionService.createUserTimeTransaction(BeanUtils.toBean(transaction, UserTimeTransactionSaveReqVO.class));
                log.info("创建用户时长交易记录-消耗, userId = {}, gameMatchId = {}, roleId = {}, timeMs = {}, transactionTimeMs = {}, transactionId = {}",
                        userId, gameMatchId, roleId, timeMs, transaction.getTransactionTimeMs(), transaction.getId());
            } else {
                transaction.setTransactionTimeMs(transaction.getTransactionTimeMs() + timeMs);
                transaction.setRemainingTimeMs(balance.getRemainingTimeMs());
                userTimeTransactionService.updateUserTimeTransaction(BeanUtils.toBean(transaction, UserTimeTransactionSaveReqVO.class));
                log.info("更新用户时长交易记录-消耗, userId = {}, gameMatchId = {}, roleId = {}, timeMs = {}, transactionTimeMs = {}, transactionId = {}",
                        userId, gameMatchId, roleId, timeMs, transaction.getTransactionTimeMs(), transaction.getId());
            }

            if (balance.getRemainingTimeMs() == 0) {
                log.info("用户时长余额不足, userId = {}, gameMatchId = {}, timeMs = {}", userId, gameMatchId, timeMs);
                return false;
            }

            return true;
        });
    }

    @Override
    public Long getRemainingTimeMs(Long userId) {
        final UserTimeBalanceDO balance = userTimeBalanceService.getUserTimeBalanceByUserId(userId);
        if (balance == null) {
            return 0L;
        }

        return balance.getRemainingTimeMs();
    }
}
